package com.secure.util;

import cn.hutool.core.collection.CollectionUtil;
import com.secure.constant.KeyConstant;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
import java.util.stream.Collectors;

/**
 * AES工具类
 * <p>
 * hutool库SecureUtil有各种加解密算法工具方法
 *
 * @author duchao
 */
public class AesUtil {

    /**
     * 算法
     */
    private static final String ALGORITHM = "AES";

    /**
     * 算法/反馈模式/填充方案
     */
    private static final String ALGORITHM_MODE_PADDING = "AES/ECB/PKCS5Padding";

    /**
     * AES密钥长度：128, 192, 256
     */
    private static final List<Integer> KEY_SIZE_LIST = CollectionUtil.toList(128, 192, 256);

    /**
     * 生成密钥(Base64编码)
     * <p>
     * 密钥长度为要求最低长度
     *
     * @return
     */
    public static String generateKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
        keyGenerator.init(KEY_SIZE_LIST.get(0));
        byte[] keyBytes = keyGenerator.generateKey().getEncoded();
        return Base64.getEncoder().encodeToString(keyBytes);
    }

    /**
     * 生成密钥(Base64编码)
     *
     * @param keySize AES密钥长度：128, 192, 256
     * @return
     */
    public static String generateKey(Integer keySize) throws Exception {
        if (!KEY_SIZE_LIST.contains(keySize)) {
            throw new IllegalArgumentException(String.format("%s加密算法的密钥长度只能为%s", ALGORITHM, KEY_SIZE_LIST.stream().map(String::valueOf).collect(Collectors.joining("、"))));
        }
        KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
        keyGenerator.init(keySize);
        byte[] keyBytes = keyGenerator.generateKey().getEncoded();
        return Base64.getEncoder().encodeToString(keyBytes);
    }

    /**
     * 加密(Base64编码)
     *
     * @param plainText 明文
     * @param key       密钥
     * @return
     */
    public static String encrypt(String plainText, String key) throws Exception {
        Cipher cipher = getCipher(key, Cipher.ENCRYPT_MODE);
        return Base64.getEncoder().encodeToString(cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)));
    }

    /**
     * 解密
     *
     * @param cipherText 密文
     * @param key        密钥
     * @return
     */
    public static String decrypt(String cipherText, String key) throws Exception {
        Cipher cipher = getCipher(key, Cipher.DECRYPT_MODE);
        return new String(cipher.doFinal(Base64.getDecoder().decode(cipherText)));
    }

    /**
     * 获取 cipher
     *
     * @param key   密钥
     * @param model 模式
     * @return
     * @throws Exception
     */
    private static Cipher getCipher(String key, int model) throws Exception {
        SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode(key), ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);
        cipher.init(model, secretKeySpec);
        return cipher;
    }

    public static void main(String[] args) throws Exception {
        //String key = generateKey();
        String key = KeyConstant.AES_DEFAULT_KEY;
        System.out.println("密钥：" + key);
        String encode = encrypt("小明", key);
        System.out.println("[小明]编码：" + encode);
        String decode = decrypt(encode, key);
        System.out.println("解码：" + decode);
    }
}
